program CustomSceneNode;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  DIrr in '..\..\DSource\DIrr.pas',
  DIrr.Vector2D in '..\..\DSource\DIrr.Vector2D.pas',
  DIrr.Vector3D in '..\..\DSource\DIrr.Vector3D.pas',
  DIrr.Video in '..\..\DSource\DIrr.Video.pas',
  DIrr.Base in '..\..\DSource\DIrr.Base.pas',
  DIrr.Types in '..\..\DSource\DIrr.Types.pas',
  DIrr.Scene in '..\..\DSource\DIrr.Scene.pas',
  DIrr.Structs in '..\..\DSource\DIrr.Structs.pas',
  DIrr.Aabbox3D in '..\..\DSource\DIrr.Aabbox3D.pas',
  DIrr.Matrix4 in '..\..\DSource\DIrr.Matrix4.pas',
  DIrr.Texture in '..\..\DSource\DIrr.Texture.pas',
  SampleCommon in '..\SampleCommon.pas',
  DIrr.Consts in '..\..\DSource\DIrr.Consts.pas';

type
  TSampleSceneNode = class(TSceneNode)
  private
    (*
    First, we declare some member variables:
    The bounding box, 4 vertices, and the material of the tetraeder.
    *)
    FBox: TAabbox3DF;
    FVertices: array[0..3] of S3DVertex;
    FMaterial: SMaterial;
    (*
    The parameters of the constructor specify the parent of the scene node,
    a pointer to the scene manager, and an id of the scene node.
    In the constructor we call the parent class' constructor,
    set some properties of the material, and
    create the 4 vertices of the tetraeder we will draw later.
    *)
  public
    constructor Create(AParent: TSceneNode; AMgr: TSceneManager; ID: S32 = -1);
    procedure OnRegisterSceneNode; override;
    procedure Render; override;
    function GetBoundingBox: PAabBox3DF; override;
    function GetMaterialCount: U32; override;
    function GetMaterial(i: U32): PMaterial; override;
  end;

{ TSampleSceneNode }

constructor TSampleSceneNode.Create(AParent: TSceneNode; AMgr: TSceneManager;
  ID: S32);
var
  i: S32;
begin
  inherited Create(AParent, AMgr, ID);

  SetName('SampleSceneNode');

  FMaterial.Init;
  FMaterial.BackfaceCulling := False;
  FMaterial.Wireframe := True;
  FMaterial.Lighting := False;

  FVertices[0].Pos.Init(0, 0, 10);
  FVertices[0].Normal.Init(1, 1, 0);
  FVertices[0].Color := [255, 0, 255, 255];
  FVertices[0].TCoords.Init(0, 1);

  FVertices[1].Pos.Init(10, 0, -10);
  FVertices[1].Normal.Init(1, 0, 0);
  FVertices[1].Color := [255, 255, 0, 255];
  FVertices[1].TCoords.Init(1, 1);

  FVertices[2].Pos.Init(0, 20, 0);
  FVertices[2].Normal.Init(0, 1, 1);
  FVertices[2].Color := [255, 255, 255, 0];
  FVertices[2].TCoords.Init(1, 0);

  FVertices[3].Pos.Init(-10, 0, -10);
  FVertices[3].Normal.Init(0, 0, 1);
  FVertices[3].Color := [255, 0, 255, 0];
  FVertices[3].TCoords.Init(0, 0);

  FBox.Reset(FVertices[0].Pos);
  for i := 1 to 3 do
  begin
    FBox.AddInternalPoint(FVertices[i].Pos);
  end;
end;

function TSampleSceneNode.GetBoundingBox: PAabBox3DF;
begin
  Result := @FBox;
end;

function TSampleSceneNode.GetMaterial(i: U32): PMaterial;
begin
  Result := @FMaterial;
end;

function TSampleSceneNode.GetMaterialCount: U32;
begin
    Result := 1;
end;

procedure TSampleSceneNode.OnRegisterSceneNode;
begin
  if IsVisible then
  begin
    SceneManager.RegisterNodeForRendering(Self);
  end;

  inherited;
end;

procedure TSampleSceneNode.Render;
var
  Indices: array of U16;
  ADriver: TVideoDriver;
begin
  Indices := [
               0, 2, 3,
               2, 1, 3,
               1, 0, 3,
               2, 0, 1
             ];

  ADriver := TVideoDriver(SceneManager.GetVideoDriver);

  ADriver.SetMaterial(FMaterial);
  ADriver.SetTransform(ETS_WORLD, AbsoluteTransformation);
  ADriver.DrawVertexPrimitiveList(@FVertices[0], 4, @Indices[0], 4,
    EVT_STANDARD, EPT_TRIANGLES, EIT_16BIT);
end;

var
  DriverType: E_DRIVER_TYPE;
  Device: TIrrlichtDevice;
  Driver: TVideoDriver;
  Smgr: TSceneManager;
  MyNode: TSampleSceneNode;
  Anim: TSceneNodeAnimator;
  Camera: TCameraSceneNode;
  Frames: U32;
begin
  try
    // ask user for driver;
    DriverType := DriverChoiceConsole;
    if DriverType = EDT_COUNT then
    begin
      ExitCode := 1;
      Exit;
    end;

    Device := createDevice(DriverType, [640, 480]);

    if not Assigned(Device) then
    begin
      ExitCode := 1;
      Exit;
    end;

    Device.SetWindowCaption('Custom Scene Node - Irrlicht Engine Demo');

    Driver := Device.GetVideoDriver;
    Smgr := Device.GetSceneManager;

    Camera := Smgr.AddCameraSceneNode(nil, Vector3DF(0, -40, 0), Vector3DF(0, 0, 0));
    Camera.Grab;

    MyNode := TSampleSceneNode.Create(Smgr.GetRootSceneNode, Smgr, 666);

    Anim := Smgr.CreateRotationAnimator([0.8, 0.0, 0.8]);
    if Assigned(Anim) then
    begin
      MyNode.AddAnimator(Anim);
      Anim.Drop;
    end;
    MyNode.Drop;

    Camera.Drop;


    //MyNode := nil;

    Frames := 0;
    while Device.Run do
    begin
      Driver.BeginScene(True, True, [0, 100, 100, 100]);
      Smgr.DrawAll;
      Driver.EndScene;

      Inc(Frames);
      if Frames = 100 then
      begin
        Device.SetWindowCaption(PChar('Irrlicht Engine [' + String(Driver.GetName) +
          '] FPS: ' + IntToStr(Driver.GetFPS)));
        Frames := 0;
      end;
    end;
    Device.Drop;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
